package com.hunliji.monitor.share.utils;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONException;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.exceptions.SignatureVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.hunliji.common.enums.CodeEnum;
import com.hunliji.common.exception.ErrorException;
import com.hunliji.common.utils.DateUtil;
import com.hunliji.monitor.share.config.JwtConfig;
import com.hunliji.monitor.share.model.AdminBO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Date;

public class JwtUtil {
    private static final Logger log = LoggerFactory.getLogger(JwtUtil.class);

    /**
     * 生成 登录令牌
     */
    public static String signToken(AdminBO token) {
        return sign(JSON.toJSONString(token));
    }

    /**
     * 解密 登录令牌
     */
    public static AdminBO unsignToken(String jwtToken) {
        String json = unsign(jwtToken);

        try {
            return JSON.parseObject(json, AdminBO.class);
        } catch (JSONException e) {
            log.error("解密登录令牌失败，json不合法");
            throw new ErrorException(CodeEnum.MANAGER_TOKEN_EXPIRE.getCode(), CodeEnum.MANAGER_TOKEN_EXPIRE.getValue());
        }
    }


    /**
     * 生成一个JWT令牌, 默认的过期时间
     *
     * @return the jwt token
     */
    public static String sign(String token) {
        return sign(token, JwtConfig.MAX_AGE);
    }

    /**
     * 生成一个JWT令牌，可设置过期时间
     *
     * @param token   令牌信息
     * @param timeout 过期时间，单位秒
     * @return the jwt token
     */
    public static String sign(String token, int timeout) {
        // 使用HS256算法
        Algorithm algorithm = Algorithm.HMAC256(JwtConfig.SECRET);

        return JWT.create()
                .withIssuer(JwtConfig.ISSUER)
                .withAudience(JwtConfig.AUDIENCE)
                .withSubject(token)
                .withExpiresAt(DateUtil.plusSeconds(new Date(), timeout))
                .sign(algorithm);
    }

    /**
     * 对JWT令牌进行解密
     *
     * @param jwtToken JWT令牌
     * @return POJO object
     */
    public static String unsign(String jwtToken) {
        DecodedJWT jwt;
        try {
            JWTVerifier verifier = JWT.require(Algorithm.HMAC256(JwtConfig.SECRET))
                    .withIssuer(JwtConfig.ISSUER)
                    .build();

            jwt = verifier.verify(jwtToken);
        }  catch (TokenExpiredException tee) {
            log.warn("jwtToken过期");
            throw new ErrorException(CodeEnum.MANAGER_TOKEN_EXPIRE.getCode(), CodeEnum.MANAGER_TOKEN_EXPIRE.getValue());
        } catch (SignatureVerificationException sve) {
            log.error("jwtToken签名异常，exception: ", sve);
            throw new ErrorException(CodeEnum.MANAGER_TOKEN_EXPIRE.getCode(), CodeEnum.MANAGER_TOKEN_EXPIRE.getValue());
        } catch (JWTDecodeException e) {
            log.error("jwtToken异常，exception: ", e);
            throw new ErrorException(CodeEnum.MANAGER_TOKEN_EXPIRE.getCode(), CodeEnum.MANAGER_TOKEN_EXPIRE.getValue());
        }

        // 验证是否有效
        Date exp = jwt.getExpiresAt();
        if (exp == null) {
            log.error("不合法token，过期时间为空");
            throw new ErrorException(CodeEnum.MANAGER_TOKEN_EXPIRE.getCode(), CodeEnum.MANAGER_TOKEN_EXPIRE.getValue());
        }
        if (exp.before(new Date())) {
            log.error("过期时间已到，token失效");
            throw new ErrorException(CodeEnum.MANAGER_TOKEN_EXPIRE.getCode(), CodeEnum.MANAGER_TOKEN_EXPIRE.getValue());
        }

        return jwt.getSubject();
    }

}
